/*
 * Copyright (C) 2021 Huawei Device Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.hudomju.swipe.adapter;

import com.hudomju.swipe.interfaces.BaseModal;

import ohos.agp.components.*;

import ohos.app.Context;

import ohos.eventhandler.EventHandler;
import ohos.eventhandler.EventRunner;
import ohos.eventhandler.InnerEvent;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Optional;

/**
 * 滑动适配器
 */
public abstract class BaseAdapter extends BaseItemProvider {
    private static final int EVENT_MESSAGE_DELAY = 1;
    private ArrayList<BaseModal> data;
    private Callbacks callbacks;
    private Context context;

    private long mDismissDelayMillis = -1;
    private MyEventHandler myHandler;
    private EventRunner runner;
    private PendingDismissData pendingDismissData = null;
    private int recoveryPosition = -1;
    private int offset = 0;

    /**
     * BaseAdapter构造方法
     *
     * @param context 上下文
     * @param data list列表数据
     * @param callbacks 回调方法
     */
    public BaseAdapter(Context context, ArrayList<BaseModal> data, Callbacks callbacks) {
        this.context = context;
        this.data = data;
        this.callbacks = callbacks;

        runner = EventRunner.create(true);
        myHandler = new MyEventHandler(runner);
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

    @Override
    public Object getItem(int position) {
        if (data != null && position >= 0 && position < data.size()) {
            return data.get(position);
        }
        return Optional.ofNullable(null);
    }

    @Override
    public int getCount() {
        return data == null ? 0 : data.size();
    }

    @Override
    public Component getComponent(int position, Component component, ComponentContainer parent) {
        ViewHolder viewHolder;
        if (component == null) {
            component = LayoutScatter.getInstance(parent.getContext()).parse(getLayoutResId(), null, false);
            viewHolder = new ViewHolder();

            // 将控件与 ViewHolder 绑定
            int[] viewIdArray = bindView();
            for (int viewId : viewIdArray) {
                viewHolder.bindViewById(component, viewId);
            }

            component.setTag(viewHolder);
        } else {
            viewHolder = (BaseAdapter.ViewHolder) component.getTag();
        }
        initData(viewHolder, data.get(position), position, callbacks);
        return component;
    }

    /**
     * 删除item
     *
     * @param position item序号
     */
    public void remove(int position) {
        if (position >= 0 && position < data.size()) {
            data.remove(position);
            notifyDataChanged();
            pendingDismissData = null;
        }
    }

    /**
     * 删除所有选中的item
     */
    public void removeAllChecked(){
        Iterator<BaseModal> iterator = data.iterator();
        while (iterator.hasNext()) {
            BaseModal baseModal = iterator.next();
            if (baseModal.getShowBack()) {
                iterator.remove();
            }
        }
        notifyDataChanged();
        pendingDismissData = null;
    }

    /**
     * 改变item状态
     *
     * @param position item序号
     */
    public void changeBackground(int position) {
        data.get(position).setShowBack(true);
        notifyDataChanged();

        recoveryPosition = -1;
    }

    /**
     * 还原item状态
     *
     * @param position item序号
     */
    public void recoveryBackground(int position) {
        if (position >= 0 && position < data.size()) {
            data.get(position).setShowBack(false);
            notifyDataChanged();
            pendingDismissData = null;
        }
    }

    /**
     * 设置延迟删除时间
     *
     * @param dismissDelayMillis 延迟时间毫秒
     */
    public void setDismissDelay(long dismissDelayMillis) {
        this.mDismissDelayMillis = dismissDelayMillis;
    }

    /**
     * 设置还原item序号
     *
     * @param position item序号
     */
    public void setRecoveryPosition(int position) {
        recoveryPosition = position;
    }

    /**
     * 延迟删除item
     *
     * @param position item序号
     */
    public void dismissDelayItem(int position) {
        performDismiss(position);
    }

    private class MyEventHandler extends EventHandler {
        private MyEventHandler(EventRunner runner) {
            super(runner);
        }

        // 重写实现processEvent方法
        @Override
        public void processEvent(InnerEvent event) {
            super.processEvent(event);
            if (event == null) {
                return;
            }
            int eventId = event.eventId;
            switch (eventId) {
                case EVENT_MESSAGE_DELAY:
                    int position = (int) event.param;
                    context.getUITaskDispatcher().asyncDispatch(new Runnable() {
                        @Override
                        public void run() {
                            if (recoveryPosition != position && position >= 0 && position < data.size()) {
                                if (data.get(position).getShowBack()) {
                                    remove(position);
                                } else {
                                    removeAllChecked();
                                }
                            } else {
                                recoveryPosition = -1;
                            }
                        }
                    });
                    break;
                default:
                    break;
            }
        }
    }

    /**
     * item的回调
     */
    public interface Callbacks {
        boolean hasActions(int position, SwipeDirection direction);

        boolean shouldDismiss(int position, SwipeDirection direction);

        void onSwipe(int position, SwipeDirection direction);

        void onItemClicked(int position);

        void onSwipeStarted(ListContainer listView, int position, SwipeDirection direction);

        void onSwipeEnded(ListContainer listView, int position, SwipeDirection direction);
    }

    /**
     * 获取 layout 文件
     *
     * @return abstract
     */
    protected abstract int getLayoutResId();

    /**
     * 将控件与 ViewHolder 绑定
     *
     * @return abstract
     */
    protected abstract int[] bindView();

    /**
     * 绑定显示数据,增加回调监听等操作
     *
     * @param holder ViewHolder
     * @param baseModal baseModal
     * @param position item位置
     * @param callbacks 回调
     */
    protected abstract void initData(ViewHolder holder, BaseModal baseModal, int position, Callbacks callbacks);

    /**
     * ViewHolder类
     */
    public static class ViewHolder {
        private HashMap<Integer, Component> viewSparseArray;

        ViewHolder() {
            viewSparseArray = new HashMap<>();
        }

        /**
         * 通过 id获取 View
         *
         * @param id item序号
         * @param <E> component
         * @return Component
         */
        public <E extends Component> E getViewById(int id) {
            return (E) viewSparseArray.get(id);
        }

        /**
         * 通过 id 获取 View并绑定到 ViewHolder
         *
         * @param view 组件
         * @param id 序号
         */
        public void bindViewById(Component view, int id) {
            viewSparseArray.put(id, view.findComponentById(id));
        }
    }

    private void addPendingDismiss(int dismissPosition) {
        int param = dismissPosition;
        InnerEvent delayInnerEvent = InnerEvent.get(EVENT_MESSAGE_DELAY, param, EventRunner.current());
        myHandler.sendEvent(delayInnerEvent, mDismissDelayMillis);
        pendingDismissData = new PendingDismissData(dismissPosition);
    }

    private void performDismiss(int dismissPosition) {
        if (pendingDismissData != null) {
            offset = offset + 1;

            boolean dismissingDifferentRow = pendingDismissData.position != dismissPosition;
            int newPosition = pendingDismissData.position < dismissPosition
                    ? dismissPosition - offset : dismissPosition;
            if (dismissingDifferentRow) {
                addPendingDismiss(newPosition);
            }
        } else {
            offset = 0;
            addPendingDismiss(dismissPosition);
        }
    }

    /**
     * PendingDismissData类
     */
    public static class PendingDismissData {
        public int position;

        /**
         * PendingDismissData构造方法
         *
         * @param position item序号
         */
        public PendingDismissData(int position) {
            this.position = position;
        }
    }
}
